package org.eli.hittable;

import org.eli.HitRecord;
import org.eli.Ray;
import org.eli.Vec3;
import org.eli.hittable.Hittable;
import org.eli.material.Material;

/**
 * 球
 */
public class Sphere implements Hittable {

    // 中心点
    private Vec3 center;

    // 半径
    private double radius;

    // 材质
    private Material matPtr;

    public Sphere(Vec3 center, double radius, Material matPtr) {
        this.center = center;
        this.radius = radius;
        this.matPtr = matPtr;
    }

    @Override
    public boolean hit(Ray r, double tMin, double tMax, HitRecord rec) {
        Vec3 oc = r.origin().subtract(center);
        double a = r.direction().sqrLength();
        double halfB = oc.dot(r.direction());
        double c = oc.sqrLength() - radius * radius;
        double discriminant = halfB * halfB - a * c;

        if (discriminant > 0) {
            double root = Math.sqrt(discriminant);
            double temp = (-halfB - root) / a;
            if (temp < tMax && temp > tMin) {
                rec.t = temp;
                rec.p = r.at(rec.t);
                Vec3 outwardNormal = rec.p.subtract(center).divide(radius);
                rec.setFaceNormal(r, outwardNormal);
                rec.matPtr = matPtr;
                return true;
            }
            temp = (-halfB + root) / a;
            if (temp < tMax && temp > tMin) {
                rec.t = temp;
                rec.p = r.at(rec.t);
                Vec3 outwardNormal = rec.p.subtract(center).divide(radius);
                rec.setFaceNormal(r, outwardNormal);
                rec.matPtr = matPtr;
                return true;
            }
        }
        return false;
    }
}
